俺のTerraform Pipeline #devio2022

俺のTerraform Pipeline #devio2022

Developers.IO 2022 〜技術で心を揺さぶる3日間〜 でTerrformのCI/CDについて発表させていただきました
Clock Icon2022.07.29

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは!AWS 事業本部コンサルティング部のたかくに(@takakuni_)です。

Developers.IO 2022 〜技術で心を揺さぶる 3 日間〜 にて、「俺の Terraform Pipeline」というテーマでお話しさせていただきました。

Terraform で CI/CD パイプラインを組むならどのような構成が取れるのか、構成例の 1 つとしてご紹介させていただきました。

動画

https://www.youtube.com/watch?v=TC6E-zW3Xns

スライド

想定する視聴者

  • そろそろ CI/CD パイプラインで Terraform を使いこなしてみようかなと言う人
  • Terraform のコードスキャン(動画だと tfsec)に興味がある人

発表ネタにしたブログ

今回は以下のブログについて、情報を掻い摘んで動画にしました。もしよければ重ねてご覧ください。

https://dev.classmethod.jp/articles/implement-cicdpipeline-terraform-202206/

情報のアップデート

ここからは先ほど紹介したブログおよび動画時点で気がつかず、今になって紹介したいことがあるので、ここからは「私自身の成長記録」をつらつらと綴っていこうと思います。

みなさんも、以前のブログ、動画、このブログでムキムキの Terraform おじさんへの階段を駆け上がっていきましょう。

Terraform の Docker イメージ

まずはじめに、Amazon ECR Public Gallery で Terraform の Docker イメージが配布されていたことです。

https://gallery.ecr.aws/hashicorp/terraform

動画時点では、terraform plan/applyコマンド用の CodeBuild プロジェクトで、毎度INSTALLフェーズにて Terraform のインストールを行なっていました。

buildspec_before.yaml
version: 0.2
env:
exported-variables: - BuildID - BuildTag
phases:
install:
runtime-versions:
golang: 1.14
commands: - "git clone https://github.com/tfutils/tfenv.git ~/.tfenv" - "ln -s ~/.tfenv/bin/\* /usr/local/bin" - "tfenv install $TF_VERSION" - "tfenv use $TF_VERSION"
pre_build:
commands: - "terraform init -input=false -no-color"
build:
commands: - "terraform plan -input=false -no-color"
post_build:
commands: - "export BuildID=`echo $CODEBUILD_BUILD_ID | cut -d: -f1`" - "export BuildTag=`echo $CODEBUILD_BUILD_ID | cut -d: -f2`"

Amazon ECR Public Gallery で配布された Terraform の Docker イメージを利用すると先ほどのINSTALLフェーズを省略することができます。

buildspec_after.yaml
version: 0.2
env:
exported-variables: - BuildID - BuildTag
phases:
pre_build:
commands: - "terraform init -input=false -no-color"
build:
commands: - "terraform plan -input=false -no-color"
post_build:
commands: - "export BuildID=`echo $CODEBUILD_BUILD_ID | cut -d: -f1`" - "export BuildTag=`echo $CODEBUILD_BUILD_ID | cut -d: -f2`"

もたらされる効果

ビルドログを確認するとネットワークの状況にもよりますが、INSTALL フェーズには「6 秒」かかったという記録が取れました。

一方で INSTALL フェーズを短縮した場合、INSTALL フェーズは「1 秒未満」まで短縮できました。

CodeBuild は実行時間あたりに対して課金が行われるため「コスト最適化」が微々たるものですが見込めます。

Build URL

ブログ時点では、CodeBuild の実行結果をレポート出力する方法として次の形式で出力を行なっていました。

https://${AWS::Region}.console.aws.amazon.com/codesuite/codebuild/${AWS::AccountId}/projects/#{TFSEC.BuildID}/build/#{TFSEC.BuildID}%3A#{TFSEC.BuildTag}/?region=${AWS::Region}

ご覧の通り、パワープレイな感じがするので調査したところ、CodeBuild でCODEBUILD_BUILD_URLという環境変数が同じ用途で使えるのでそちらにアップデートを行います。

buildspec.yaml
version: 0.2
env:
exported-variables:
-     - BuildID
-     - BuildTag
+     - BUILD_URL
  phases:
  pre_build:
  commands: - "terraform init -input=false -no-color"
  build:
  commands: - "terraform plan -input=false -no-color"
  post_build:
  commands:
-       - "export BuildID=`echo $CODEBUILD_BUILD_ID | cut -d: -f1`"
-       - "export BuildTag=`echo $CODEBUILD_BUILD_ID | cut -d: -f2`"
+       - "export BUILD_URL=`echo $CODEBUILD_BUILD_URL`"

Cloudformartion テンプレートもかなりスッキリしたのがわかります。

terraform_pipeline.yaml
  CodePipeline:
    Type: AWS::CodePipeline::Pipeline
    Properties:
      Name: !Sub "${PrjPrefix}-tf-pipeline"
      ArtifactStore:
        EncryptionKey:
          Id: !GetAtt KeyS3Arthifact.Arn
          Type: "KMS"
        Location: !Ref BucketArtifacts
        Type: "S3"
      RoleArn: !GetAtt RoleTfPipelne.Arn
      Stages:
        - Name: "Source"
          Actions:
            - Name: "CodeCommit_Source"
              ActionTypeId:
                Category: "Source"
                Owner: "AWS"
                Provider: "CodeCommit"
                Version: "1"
              Configuration:
                RepositoryName: !GetAtt CodeCommit.Name
                BranchName: !Ref BranchName
                PollForSourceChanges: false
              OutputArtifacts:
                - Name: "Artifact_Source_CodeCommit_Source"
              RoleArn: !GetAtt RoleTfPipelne.Arn
              RunOrder: 1
        - Name: "tfsec_Stage"
          Actions:
            - Name: "Terraform_Security_Analysis"
              Namespace: TFSEC
              ActionTypeId:
                Category: "Build"
                Owner: "AWS"
                Provider: "CodeBuild"
                Version: "1"
              Configuration:
                ProjectName: !Ref ProjectTfsec
              InputArtifacts:
                - Name: "Artifact_Source_CodeCommit_Source"
              RoleArn: !GetAtt RoleTfPipelne.Arn
              RunOrder: 1
        - Name: "Terraform_Stages"
          Actions:
            - Name: "Terraform_Security_Analysis_Manual_Review"
              ActionTypeId:
                Category: "Approval"
                Owner: "AWS"
                Provider: "Manual"
                Version: "1"
              Configuration:
                CustomData: "tfsec review"
-               ExternalEntityLink: !Sub "https://${AWS::Region}.console.aws.amazon.com/codesuite/codebuild/${AWS::AccountId}/projects/#{TFSEC.BuildID}/build/#{TFSEC.BuildID}%3A#{TFSEC.BuildTag}/?region=${AWS::Region}"
+               ExternalEntityLink: "#{TFSEC.BUILD_URL}"
              RoleArn: !GetAtt RoleTfPipelne.Arn
              RunOrder: 1
            - Name: "Terraform_Plan"
              Namespace: "TERRAFORM"
              ActionTypeId:
                Category: "Build"
                Owner: "AWS"
                Provider: "CodeBuild"
                Version: "1"
              Configuration:
                ProjectName: !Ref ProjectTfplan
              InputArtifacts:
                - Name: "Artifact_Source_CodeCommit_Source"
              RoleArn: !GetAtt RoleTfPipelne.Arn
              RunOrder: 2
            - Name: "Terraform_Plan_Manual_Review"
              ActionTypeId:
                Category: "Approval"
                Owner: "AWS"
                Provider: "Manual"
                Version: "1"
              Configuration:
                CustomData: "Terraform plan review"
-               ExternalEntityLink: !Sub "https://${AWS::Region}.console.aws.amazon.com/codesuite/codebuild/${AWS::AccountId}/projects/#{TERRAFORM.BuildID}/build/#{TERRAFORM.BuildID}%3A#{TERRAFORM.BuildTag}/?region=${AWS::Region}"
+               ExternalEntityLink: "#{TERRAFORM.BUILD_URL}"
              RoleArn: !GetAtt RoleTfPipelne.Arn
              RunOrder: 3
            - Name: "Terraform_Apply"
              ActionTypeId:
                Category: "Build"
                Owner: "AWS"
                Provider: "CodeBuild"
                Version: "1"
              Configuration:
                ProjectName: !Ref ProjectTfapply
              InputArtifacts:
                - Name: "Artifact_Source_CodeCommit_Source"
              RoleArn: !GetAtt RoleTfPipelne.Arn
              RunOrder: 4

Snyk IaC もイイぞ

Snyk IaC は、tfsec の代替案として有効なソリューションです。

最近ブログもよく書いているので、重ねてご覧いただければ嬉しいです。

https://dev.classmethod.jp/articles/snyk-infrastructure-as-code-security-overview/

https://dev.classmethod.jp/articles/codebuild-curated-image-from-snyk-official-image/

DevelopersIO 2022 で Snyk Japan の相澤様に登壇いただきました。(セッションレポートになります。)

https://dev.classmethod.jp/articles/devio2022-snyk-iac/

まとめ

「俺の Terraform Pipeline」の登壇レポートでした!「俺の Terraform Pipeline」を作ろうとしている方の参考になれば幸いです。

以上、AWS 事業本部コンサルティング部のたかくに(@takakuni_)でした!

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.